/*
 *  +----------------------------------------------------------------------
 *  | sophon [ A FAST GAME FRAMEWORK ]
 *  +----------------------------------------------------------------------
 *  | Copyright (c) 2023-2029 All rights reserved.
 *  +----------------------------------------------------------------------
 *  | Licensed ( http:www.apache.org/licenses/LICENSE-2.0 )
 *  +----------------------------------------------------------------------
 *  | Author: jqiris <1920624985@qq.com>
 *  +----------------------------------------------------------------------
 */

use config::Config;
use conhash::{ConsistentHash, Node};
use etcd_client::{Client, Error};
use nats::{self, IntoServerList};

use rsa::{Pkcs1v15Encrypt, PublicKey, RsaPrivateKey, RsaPublicKey};
use sophon::prelude::*;

#[test]
fn nats_connect() {
    let urls = "localhost:4322,localhost:4323,localhost:4324".into_server_list();
    let nc = nats::Options::with_user_pass("nats", "@kungfu2021")
        .connect(urls)
        .expect("connection failed");
    nc.publish("my.subject", "my message")
        .expect("publish failed");
    let sub = nc
        .subscribe("my.subject")
        .unwrap()
        .with_handler(move |msg| {
            println!("Received {}", &msg);
            // msg.respond(msg);
            Ok(())
        });
    // nc.request(subject, msg)
}

#[test]
fn etcd_test() {
    let res = etcd_connect();
    match res {
        Ok(_) => println!("{}", "run ok"),
        Err(err) => println!("{}", err),
    }
}

#[tokio::main]
async fn etcd_connect() -> Result<(), Error> {
    let urls = &["127.0.0.1:23791", "127.0.0.1:23792", "127.0.0.1:23793"];
    let mut client = Client::connect(urls, None).await?;
    // put kv
    client.put("foo", "bar", None).await?;
    // get kv
    let resp = client.get("foo", None).await?;
    if let Some(kv) = resp.kvs().first() {
        println!("Get kv: {{{}: {}}}", kv.key_str()?, kv.value_str()?);
    }
    // let (mut watcher, mut stream) = client.watch("foo", None).await?;
    // while let Some(resp) = stream.message().await? {
    //     println!("[{}] receive watch response", resp.watch_id());
    //     println!("compact revision: {}", resp.compact_revision());

    //     if resp.created() {
    //         println!("watcher created: {}", resp.watch_id());
    //     }

    //     if resp.canceled() {
    //         watch_count -= 1;
    //         println!("watch canceled: {}", resp.watch_id());
    //         if watch_count == 0 {
    //             break;
    //         }
    //     }

    //     for event in resp.events() {
    //         println!("event type: {:?}", event.event_type());
    //         if let Some(kv) = event.kv() {
    //             println!("kv: {{{}: {}}}", kv.key_str()?, kv.value_str()?);
    //         }

    //         if EventType::Delete == event.event_type() {
    //             watcher.cancel_by_id(resp.watch_id()).await?;
    //         }
    //     }

    //     println!();
    // }
    Ok(())
}

#[test]
fn config_test() {
    let settings = Config::builder()
        // Add in `./Settings.toml`
        .add_source(config::File::with_name("./config.toml"))
        // Add in settings from the environment (with a prefix of APP)
        // Eg.. `APP_DEBUG=1 ./target/app` would set the `debug` key
        .add_source(config::Environment::with_prefix("APP"))
        .build()
        .unwrap();

    // let rpcConf = RpcConf {};
    // Print out our settings (as a HashMap)
    println!("{:?}", settings.get::<RpcConf>("discover").unwrap());
}

#[test]
fn load_config() {
    init_frame("./config.toml");
    let rpc_cfg = get_rpc_conf();
    println!("rpc conf:{:?}", rpc_cfg);
    let discover_cfg = get_discover_conf();
    println!("discover conf:{:?}", discover_cfg);
}

#[test]
fn i64frompointer() {
    let a: i64 = 23;
    let b = &a;
    println!("i64:{}", b.to_owned());
}

#[derive(Debug, Clone)]
pub struct HashNode<T>
where
    T: Clone,
{
    data: T,
}

impl<T: Clone> HashNode<T> {
    fn new(data: T) -> Self {
        Self { data }
    }
}

impl Node for HashNode<Server> {
    fn name(&self) -> String {
        format!("{}:{}", self.data.server_name, self.data.server_id)
    }
}

#[test]
fn conhash_test() {
    const REPLICAS: usize = 20;
    let mut ch = ConsistentHash::new();
    let server1 = HashNode::new(Server {
        server_type: "a".to_owned(),
        server_id: "a001".to_owned(),
        ..Default::default()
    });
    ch.add(&server1, REPLICAS);
    let server2 = HashNode::new(Server {
        server_type: "a".to_owned(),
        server_id: "a002".to_owned(),
        ..Default::default()
    });
    ch.add(&server2, REPLICAS);
    let server3 = HashNode::new(Server {
        server_type: "b".to_owned(),
        server_id: "b001".to_owned(),
        ..Default::default()
    });
    ch.add(&server3, REPLICAS);
    let node = ch.get("b".as_bytes()).unwrap();
    println!("node is:{:?}", node);
}

#[test]
fn rsq_test() {
    let mut rng = rand::thread_rng();

    let bits = 2048;
    let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
    let public_key = RsaPublicKey::from(&private_key);

    // Encrypt
    let data = b"hello world";
    let enc_data = public_key
        .encrypt(&mut rng, Pkcs1v15Encrypt, &data[..])
        .expect("failed to encrypt");
    assert_ne!(&data[..], &enc_data[..]);

    // Decrypt
    let dec_data = private_key
        .decrypt(Pkcs1v15Encrypt, &enc_data)
        .expect("failed to decrypt");
    assert_eq!(&data[..], &dec_data[..]);
}
